package bma.common.netty.tester;

import java.util.concurrent.Executor;
import java.util.concurrent.Executors;

import org.jboss.netty.bootstrap.ClientBootstrap;
import org.jboss.netty.channel.Channel;
import org.jboss.netty.channel.ChannelFuture;
import org.jboss.netty.channel.ChannelFutureListener;
import org.jboss.netty.channel.ChannelHandler;
import org.jboss.netty.channel.ChannelPipeline;
import org.jboss.netty.channel.ChannelPipelineFactory;
import org.jboss.netty.channel.Channels;
import org.jboss.netty.channel.socket.nio.NioClientSocketChannelFactory;

import bma.common.langutil.concurrent.Event;
import bma.common.langutil.io.HostPort;
import bma.common.langutil.log.LogPrinter;
import bma.common.langutil.log.LogPrinter.LEVEL;
import bma.common.langutil.pipeline.CommonPipelineBuilder;
import bma.common.netty.NettyChannelPipeline;
import bma.common.netty.handler.ChannelHandlerLog;
import bma.common.netty.handler.ChannelHandlerLog.TYPE;

public class NettyClientTester {

	final org.slf4j.Logger log = org.slf4j.LoggerFactory
			.getLogger(NettyClientTester.class);

	private CommonPipelineBuilder<ChannelHandler> clientBuilder;

	public CommonPipelineBuilder<ChannelHandler> getClientBuilder() {
		return clientBuilder;
	}

	public void setClientBuilder(
			CommonPipelineBuilder<ChannelHandler> clientBuilder) {
		this.clientBuilder = clientBuilder;
	}

	protected ChannelPipelineFactory clientFactory() {
		return new ChannelPipelineFactory() {

			@Override
			public ChannelPipeline getPipeline() throws Exception {
				ChannelPipeline p = Channels.pipeline(); // Note the static
															// import.
				if (clientBuilder != null) {
					clientBuilder.buildPipeline(new NettyChannelPipeline(p));
				}
				p.addFirst("log", new ChannelHandlerLog(new LogPrinter(log,
						LEVEL.DEBUG), TYPE.ALL, 1024 * 1000));
				return p;
			}
		};
	}

	private Channel clientChannel;
	private Event event = new Event(false);

	public Channel start(String remote, int port, long time) throws Exception {

		System.err.println("start ClientTester *:" + remote + ":" + port);

		// Configure the bootstrap.
		Executor executor = Executors.newCachedThreadPool();

		ClientBootstrap cb = new ClientBootstrap(
				new NioClientSocketChannelFactory(executor, executor));
		cb.setPipelineFactory(clientFactory());

		cb.connect(new HostPort(remote, port).createInetSocketAddress())
				.addListener(new ChannelFutureListener() {

					@Override
					public void operationComplete(ChannelFuture future)
							throws Exception {
						clientChannel = future.getChannel();
						event.setEvent();
					}
				});
		event.checkAndWait(time);
		return clientChannel;
	}

	public void close() {
		if (clientChannel != null) {
			clientChannel.close();
		}
	}
}
